package com.lost.octopus.es.processor.web.controller.base;

import com.google.gson.Gson;
import com.sunsharing.share.boot.framework.annotation.ShareRest;
import com.sunsharing.share.common.base.exception.ShareBusinessException;
import com.sunsharing.share.common.base.exception.ShareResponseCode;
import com.lost.octopus.es.processor.entity.PageIn;
import com.lost.octopus.es.helper.entity.model.QueryBuilder;
import com.lost.octopus.es.helper.entity.query.QueryResult;
import com.lost.octopus.es.helper.service.DocumentEsService;
import com.lost.octopus.es.processor.resolver.EsShareListRequest;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * es单位信息查询
 * @author zhangbh
 **/
@Log4j2
@ShareRest
@RequestMapping("es")
public class BaseController {

    /**
     * 通用es操作服务
     */
    @Resource
    private DocumentEsService documentEsService;
    /**
     * 序列化，默认空不序列化
     */
    private static final Gson GSON = new Gson();

    /**
     * shareList查询包装
     * @param request 请求
     * @param clazz 返回类型
     * @param businessName 业务说明
     * @param <T> 类型
     * @return 请求数据
     */
    protected <T> QueryResult<T> searchPage(EsShareListRequest<?> request, Class<T> clazz, String businessName) {
        if (clazz == null) {
            log.error(businessName + "业务查询异常，需要传递查询参数，否则无法解析clazz");
            throw new ShareBusinessException(ShareResponseCode.INNER_SYSTEM_ERROR.getCode(), businessName + "业务查询异常，需要传递查询参数");
        }
        PageIn page = request.getPage();
        if (page == null) {
            page = new PageIn.PageInBuilder().build();
        }
        try {
            QueryBuilder of = QueryBuilder.of(page.getCurrentPage(), page.getLinesPerPage(), request.getData());
            // 检查其他配置
            checkExtSetting(request, of);
            return documentEsService.boolSearch(of, clazz);
        } catch (IOException e) {
            log.error("查询异常", e);
            throw new ShareBusinessException(ShareResponseCode.INNER_SYSTEM_ERROR.getCode(), businessName + "业务查询异常");
        }
    }

    private void checkExtSetting(EsShareListRequest<?> request, QueryBuilder of) {
        // 是否打印日志
        if (request.isPrintLog()) {
            log.info("当前查询对象{}", GSON.toJson(request));
        }
        // 匹配度排序
        of.getSearchBuilder().explain(request.isExplain());
        // 检查高亮
        checkHighlight(request, of);
        // 默认启用排序
        addCustomSort(request, of);
    }

    private void addCustomSort(EsShareListRequest<?> request, QueryBuilder of) {
        of.setNeedSort(request.isNeedSort());
        if (CollectionUtils.isEmpty(request.getSorts())) {
            return;
        }
        // 自定义排序
        List<FieldSortBuilder> customSort = request.getSorts().stream()
            .map(sort -> SortBuilders.fieldSort(sort.getFieldName()).unmappedType(sort.getUnmappedType())
                .order(SortOrder.valueOf(sort.getOrder().name())))
            .collect(Collectors.toList());
        of.setSorts(customSort);
    }

    /**
     * 设置文本高亮，目前简单配置
     * @param request 请求
     * @param of es请求构建器
     */
    private void checkHighlight(EsShareListRequest<?> request, QueryBuilder of) {
        // 是否设置高亮
        if (StringUtils.isBlank(request.getHighlightField())) {
            return;
        }
        HighlightBuilder highlighter = new HighlightBuilder();
        highlighter.field(request.getHighlightField()).requireFieldMatch(false)
            // 增加高亮标签
            .preTags("<span style=\"color:red\" class=\"standard-active\">").postTags("</span>");
        of.getSearchBuilder().highlighter(highlighter);
    }
}
